/************************************************************************
*
*  LibTLib
*  Copyright (C) 2010  Thor Qin
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
*
* Author: Thor Qin
* Bug Report: thor.qin@gmail.com
*
**************************************************************************/

#ifndef TLIBUSTR_H_
#define TLIBUSTR_H_

#include "tlibbase.h"
#include <string>
#include <locale>

namespace tlib {


int unichar_to_utf8(wchar_t c, char *outbuf);
wchar_t unichar_from_utf8(const char* p, int* plen = 0);

// UTF8 string.
class ustring
{
public:
	typedef std::string::size_type size_type;
	static const size_type npos;

	ustring();
	ustring(const ustring& src);
	ustring(const ustring& src, ustring::size_type i, ustring::size_type n);
	// Initialize with std::string that encoded with UTF8.
	ustring(const std::string& src);
	// Initialize with std::wstring.
	ustring(const std::wstring& src);
	// Initialize with C string that encoded with UTF8.
	ustring(const char* src);
	// Initialize with C string that encoded with UTF8.
	ustring(const char* src, size_type size);
	// Initialize with C unicode string.
	ustring(const wchar_t* src);
	// Initialize with C unicode string.
	ustring(const wchar_t* src, size_type size);

	ustring(size_type n, char src);
	ustring(size_type n, wchar_t src);

	inline void swap(ustring& other);

	// Convert
	operator const std::string&() const;
	operator std::string() const;
	operator std::wstring() const;
	const char* data()  const;
	const char* c_str() const;

	// Assign
	ustring& assign(const char* src, size_type size);
	ustring& assign(const wchar_t* src, size_type size);
	ustring& assign(ustring::size_type n, wchar_t uc);
	ustring& assign(ustring::size_type n, char c);
	ustring& operator=(const std::string& src);
	ustring& operator=(const ustring& src);
	ustring& operator=(const std::wstring& src);
	ustring& operator=(const char* src);
	ustring& operator=(const wchar_t* src);
	ustring& operator=(const wchar_t uc);
	ustring& operator=(const char c);

	// Append
	ustring& append(const char* src, size_type size);
	ustring& append(const wchar_t* src, size_type size);
	ustring& append(size_type n, const char c);
	ustring& append(size_type n, const wchar_t uc);
	ustring& operator+=(const std::string& other);
	ustring& operator+=(const ustring& other);
	ustring& operator+=(const std::wstring& other);
	ustring& operator+=(const char* other);
	ustring& operator+=(const wchar_t* other);
	ustring& operator+=(wchar_t uc);
	ustring& operator+=(char c);
	void push_back(wchar_t uc);
	void push_back(char c);

	// Insert
	ustring& insert(size_type i, const char* src, size_type size);
	ustring& insert(size_type i, const wchar_t* src, size_type size);
	ustring& insert (size_type i, const std::string& src);
	ustring& insert (size_type i, const ustring& src);
	ustring& insert (size_type i, const std::wstring& src);
	ustring& insert (size_type i, const char* src);
	ustring& insert (size_type i, const wchar_t* src);
	ustring& insert (size_type i, size_type n, const wchar_t uc);
	ustring& insert (size_type i, size_type n, const char c);

	// compare
	int compare(const ustring& src) const;
	int compare(const std::string& src) const;
	int compare(const std::wstring& src) const;
	int compare(const char* src) const;
	int compare(const wchar_t* src) const;

	// Erase
	void clear();
	ustring& erase(size_type i, size_type n=npos);
	ustring& erase();

	// Utilities
	ustring& replace(size_type i, size_type n, const ustring& src);
	size_type find(const ustring& str, size_type i = 0) const;
	inline ustring substr(size_type i = 0, size_type n = npos) const;
	ustring lowercase() const;
	ustring uppercase() const;
	wchar_t operator [] (size_t index) const;

	// Store
	bool empty() const;
	size_type length() const;
	size_type size() const;
	size_type bytes() const;
	void resize(size_type n, wchar_t uc);
	void resize(size_type n, char c = '\0');
	size_type capacity() const;
	size_type max_size() const;
	void reserve(size_type n = 0);

private:
	std::string _str;
};

inline void ustring::swap(ustring& other)
{
	_str.swap(other._str);
}

inline
void swap(ustring& lhs, ustring& rhs)
{
	lhs.swap(rhs);
}

inline
ustring ustring::substr(size_type i, size_type n) const
{
	return ustring(*this, i, n);
}

// Operator ==
inline bool operator==(const ustring& lhs, const ustring& rhs)
{
	return (lhs.compare(rhs) == 0);
}
inline bool operator==(const ustring& lhs, const char* rhs)
{
	return (lhs.compare(rhs) == 0);
}
inline bool operator==(const ustring& lhs, const wchar_t* rhs)
{
	return (lhs.compare(rhs) == 0);
}
inline bool operator==(const char* lhs, const ustring& rhs)
{
	return (rhs.compare(lhs) == 0);
}
inline bool operator==(const wchar_t* lhs, const ustring& rhs)
{
	return (rhs.compare(lhs) == 0);
}
// Operator !=
inline bool operator!=(const ustring& lhs, const ustring& rhs)
{
	return (lhs.compare(rhs) != 0);
}
inline bool operator!=(const ustring& lhs, const char* rhs)
{
	return (lhs.compare(rhs) != 0);
}
inline bool operator!=(const ustring& lhs, const wchar_t* rhs)
{
	return (lhs.compare(rhs) != 0);
}
inline bool operator!=(const char* lhs, const ustring& rhs)
{
	return (rhs.compare(lhs) != 0);
}
inline bool operator!=(const wchar_t* lhs, const ustring& rhs)
{
	return (rhs.compare(lhs) != 0);
}
// Operator <
inline bool operator<(const ustring& lhs, const ustring& rhs)
{
	return (lhs.compare(rhs) < 0);
}
inline bool operator<(const ustring& lhs, const char* rhs)
{
	return (lhs.compare(rhs) < 0);
}
inline bool operator<(const ustring& lhs, const wchar_t* rhs)
{
	return (lhs.compare(rhs) < 0);
}
inline bool operator<(const char* lhs, const ustring& rhs)
{
	return (rhs.compare(lhs) > 0);
}
inline bool operator<(const wchar_t* lhs, const ustring& rhs)
{
	return (rhs.compare(lhs) > 0);
}
// Operator >
inline bool operator>(const ustring& lhs, const ustring& rhs)
{
	return (lhs.compare(rhs) > 0);
}
inline bool operator>(const ustring& lhs, const char* rhs)
{
	return (lhs.compare(rhs) > 0);
}
inline bool operator>(const ustring& lhs, const wchar_t* rhs)
{
	return (lhs.compare(rhs) > 0);
}
inline bool operator>(const char* lhs, const ustring& rhs)
{
	return (rhs.compare(lhs) < 0);
}
inline bool operator>(const wchar_t* lhs, const ustring& rhs)
{
	return (rhs.compare(lhs) < 0);
}
// Operator <=
inline bool operator<=(const ustring& lhs, const ustring& rhs)
{
	return (lhs.compare(rhs) <= 0);
}
inline bool operator<=(const ustring& lhs, const char* rhs)
{
	return (lhs.compare(rhs) <= 0);
}
inline bool operator<=(const ustring& lhs, const wchar_t* rhs)
{
	return (lhs.compare(rhs) <= 0);
}
inline bool operator<=(const char* lhs, const ustring& rhs)
{
	return (rhs.compare(lhs) >= 0);
}
inline bool operator<=(const wchar_t* lhs, const ustring& rhs)
{
	return (rhs.compare(lhs) >= 0);
}
// Operator >=
inline bool operator>=(const ustring& lhs, const ustring& rhs)
{
	return (lhs.compare(rhs) >= 0);
}
inline bool operator>=(const ustring& lhs, const char* rhs)
{
	return (lhs.compare(rhs) >= 0);
}
inline bool operator>=(const ustring& lhs, const wchar_t* rhs)
{
	return (lhs.compare(rhs) >= 0);
}
inline bool operator>=(const char* lhs, const ustring& rhs)
{
	return (rhs.compare(lhs) <= 0);
}
inline bool operator>=(const wchar_t* lhs, const ustring& rhs)
{
	return (rhs.compare(lhs) <= 0);
}


inline ustring operator+(const ustring& lhs, const ustring& rhs)
{
	ustring temp(lhs);
	temp += rhs;
	return temp;
}
inline ustring operator+(const ustring& lhs, const char* rhs)
{
	ustring temp(lhs);
	temp += rhs;
	return temp;
}
inline ustring operator+(const ustring& lhs, const wchar_t* rhs)
{
	ustring temp(lhs);
	temp += rhs;
	return temp;
}
inline ustring operator+(const char* lhs, const ustring& rhs)
{
	ustring temp(lhs);
	temp += rhs;
	return temp;
}
inline ustring operator+(const wchar_t* lhs, const ustring& rhs)
{
	ustring temp(lhs);
	temp += rhs;
	return temp;
}
inline ustring operator+(const ustring& lhs, wchar_t rhs)
{
	ustring temp(lhs);
	temp += rhs;
	return temp;
}
inline ustring operator+(wchar_t lhs, const ustring& rhs)
{
	ustring temp(1, lhs);
	temp += rhs;
	return temp;
}
inline ustring operator+(const ustring& lhs, char rhs)
{
	ustring temp(lhs);
	temp += rhs;
	return temp;
}
inline ustring operator+(char lhs, const ustring& rhs)
{
	ustring temp(1, lhs);
	temp += rhs;
	return temp;
}




typedef std::codecvt<wchar_t, char, std::mbstate_t> wchar_codecvt_base;
class codecvt_utf16_le: public wchar_codecvt_base
{
public:
    typedef std::codecvt_base::result result;
    typedef wchar_t intern_type;
    typedef char extern_type;
    typedef std::mbstate_t state_type;

	explicit codecvt_utf16_le(size_t refs = 0);
protected:
    virtual result
    do_out(state_type& state, const intern_type* from,
	     const intern_type* from_end, const intern_type*& from_next,
	     extern_type* to, extern_type* to_end,
	     extern_type*& to_next) const;

    virtual result
    do_unshift(state_type& state, extern_type* to,
		 extern_type* to_end, extern_type*& to_next) const;

    virtual result
    do_in(state_type& state, const extern_type* from,
	    const extern_type* from_end, const extern_type*& from_next,
	    intern_type* to, intern_type* to_end,
	    intern_type*& to_next) const;

    // Returns the width of an internal character in terms of external characters,
    // if this is a fixed value.
    // Otherwise, if this is a variable value, the function returns 0.
    // Alternatively, if the encoding of an external sequence is state-dependent, the function returns -1.
    virtual int
    do_encoding() const throw();

    virtual bool
    do_always_noconv() const throw();

    // Returns the amount of external characters in the range [from,from_end)
    // that could be translated into at maximum max internal characters
    virtual int
    do_length(state_type&, const extern_type* from,
		const extern_type* from_end, size_t max) const;

    // Returns the maximum amount of external characters needed for one internal character.
    virtual int
    do_max_length() const throw();
};



class codecvt_utf16_be: public wchar_codecvt_base
{
public:
    typedef std::codecvt_base::result result;
    typedef wchar_t intern_type;
    typedef char extern_type;
    typedef std::mbstate_t state_type;

	explicit codecvt_utf16_be(size_t refs = 0);
protected:
    virtual result
    do_out(state_type& state, const intern_type* from,
	     const intern_type* from_end, const intern_type*& from_next,
	     extern_type* to, extern_type* to_end,
	     extern_type*& to_next) const;

    virtual result
    do_unshift(state_type& state, extern_type* to,
		 extern_type* to_end, extern_type*& to_next) const;

    virtual result
    do_in(state_type& state, const extern_type* from,
	    const extern_type* from_end, const extern_type*& from_next,
	    intern_type* to, intern_type* to_end,
	    intern_type*& to_next) const;

    // Returns the width of an internal character in terms of external characters,
    // if this is a fixed value.
    // Otherwise, if this is a variable value, the function returns 0.
    // Alternatively, if the encoding of an external sequence is state-dependent, the function returns -1.
    virtual int
    do_encoding() const throw();

    virtual bool
    do_always_noconv() const throw();

    // Returns the amount of external characters in the range [from,from_end)
    // that could be translated into at maximum max internal characters
    virtual int
    do_length(state_type&, const extern_type* from,
		const extern_type* from_end, size_t max) const;

    // Returns the maximum amount of external characters needed for one internal character.
    virtual int
    do_max_length() const throw();
};


typedef std::codecvt<char, char, std::mbstate_t> char_codecvt_base;

// Internal charset is utf8 external charset is unicode-le.
class codecvt_char_utf16_le: public char_codecvt_base
{
public:
    typedef std::codecvt_base::result result;
    typedef char intern_type;
    typedef char extern_type;
    typedef std::mbstate_t state_type;

	explicit codecvt_char_utf16_le(size_t refs = 0);
protected:
    virtual result
    do_out(state_type& state, const intern_type* from,
	     const intern_type* from_end, const intern_type*& from_next,
	     extern_type* to, extern_type* to_end,
	     extern_type*& to_next) const;

    virtual result
    do_unshift(state_type& state, extern_type* to,
		 extern_type* to_end, extern_type*& to_next) const;

    virtual result
    do_in(state_type& state, const extern_type* from,
	    const extern_type* from_end, const extern_type*& from_next,
	    intern_type* to, intern_type* to_end,
	    intern_type*& to_next) const;

    // Returns the width of an internal character in terms of external characters,
    // if this is a fixed value.
    // Otherwise, if this is a variable value, the function returns 0.
    // Alternatively, if the encoding of an external sequence is state-dependent, the function returns -1.
    virtual int
    do_encoding() const throw();

    virtual bool
    do_always_noconv() const throw();

    // Returns the amount of external characters in the range [from,from_end)
    // that could be translated into at maximum max internal characters
    virtual int
    do_length(state_type&, const extern_type* from,
		const extern_type* from_end, size_t max) const;

    // Returns the maximum amount of external characters needed for one internal character.
    virtual int
    do_max_length() const throw();
};




// Internal charset is utf8 external charset is unicode-le.
class codecvt_char_utf16_be: public char_codecvt_base
{
public:
    typedef std::codecvt_base::result result;
    typedef char intern_type;
    typedef char extern_type;
    typedef std::mbstate_t state_type;

	explicit codecvt_char_utf16_be(size_t refs = 0);
protected:
    virtual result
    do_out(state_type& state, const intern_type* from,
	     const intern_type* from_end, const intern_type*& from_next,
	     extern_type* to, extern_type* to_end,
	     extern_type*& to_next) const;

    virtual result
    do_unshift(state_type& state, extern_type* to,
		 extern_type* to_end, extern_type*& to_next) const;

    virtual result
    do_in(state_type& state, const extern_type* from,
	    const extern_type* from_end, const extern_type*& from_next,
	    intern_type* to, intern_type* to_end,
	    intern_type*& to_next) const;

    // Returns the width of an internal character in terms of external characters,
    // if this is a fixed value.
    // Otherwise, if this is a variable value, the function returns 0.
    // Alternatively, if the encoding of an external sequence is state-dependent, the function returns -1.
    virtual int
    do_encoding() const throw();

    virtual bool
    do_always_noconv() const throw();

    // Returns the amount of external characters in the range [from,from_end)
    // that could be translated into at maximum max internal characters
    virtual int
    do_length(state_type&, const extern_type* from,
		const extern_type* from_end, size_t max) const;

    // Returns the maximum amount of external characters needed for one internal character.
    virtual int
    do_max_length() const throw();
};


} // End namespace

#endif /* TLIBUSTR_H_ */
